﻿using DingTalk.Models;
using DingTalkByHttp;
using DingTalkByHttp.Helper;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace Service
{
    public class DingTalkApi
    {
        private static DingTalkApi _dingTalkApi;
        private static DateTime _getTime = DateTime.MinValue;
        private static string _appKey = ConfigurationManager.AppSettings["Dd:appkey"];//钉钉唯一应用表示
        private static string _appSecret = ConfigurationManager.AppSettings["Dd:appsecret"];//钉钉应用密钥
        private static string _accessToken = "00a4a6a9a9343e9294638f219376e90b";//钉钉调用接口凭证
        private static long _agentId = long.Parse(ConfigurationManager.AppSettings["Dd:agentid"]);
        private static string _corpId = ConfigurationManager.AppSettings["Dd:corpid"];

        /// <summary>
        /// 定义私有构造函数，使外界不能创建本类实例
        /// </summary>
        private DingTalkApi()
        {
            GetAccessToken();
        }
        public static DingTalkApi GetInstance()
        {
            if (_dingTalkApi == null)
            {
                _dingTalkApi = new DingTalkApi();
            }
            return _dingTalkApi;
        }
        /// <summary>
        /// 如果是第一次获取token或者token的时效超过两小时(检查token是否过期)
        /// </summary>
        private static void CheckAccessToken()
        {
            if (string.IsNullOrWhiteSpace(_accessToken) || (DateTime.Now - _getTime).Seconds > 7200)
            {
                GetAccessToken();
            }
        }

        /// <summary>
        /// 获取企业微信token
        /// </summary>
        private static void GetAccessToken()
        {
            try
            {
                string url = "https://api.dingtalk.com/v1.0/oauth2/accessToken";

                string postData = JsonConvert.SerializeObject(new
                {
                    appKey = _appKey,
                    appSecret = _appSecret
                });
                var result = WebApiHelper.CallPostWebApi(url, postData);
                JObject jObject = JObject.Parse(result);
                string token = jObject["accessToken"].ToString();
                _accessToken = token;

            }
            catch (Exception e)
            {

                throw e;
            }
        }
        /// <summary>
        /// 根据手机号获取userid
        /// </summary>
        public string GetUserIDByMobile(string mobile)
        {
            string userId = "";
            try
            {
                string url = "https://oapi.dingtalk.com/topapi/v2/user/getbymobile?access_token=";

                string postData = JsonConvert.SerializeObject(new
                {
                    mobile = mobile,
                    support_exclusive_account_search = "true"
                });
                var result = WebApiHelper.CallPostWebApi(url + _accessToken, postData);
                JObject jObject = JObject.Parse(result);
                string erro = jObject["errcode"].ToString();
                if (erro == "88")//accessToken失效
                {
                    GetAccessToken();
                    result = WebApiHelper.CallPostWebApi(url + _accessToken, postData);
                    jObject = JObject.Parse(result);
                }
                else if (erro != "0")
                {
                    throw new Exception("钉钉获取UserID失败" + erro + jObject["sub_msg"].ToString());
                }
                userId = jObject["result"]["userid"].ToString();
            }
            catch (Exception e)
            {

                throw e;
            }
            return userId;
        }
        /// <summary>
        /// 获取用户详情
        /// </summary>
        public DingUserInfoModel GetUserInfoByUserID(string userId)
        {
            DingUserInfoModel userInfo = null;
            try
            {
                string url = "https://oapi.dingtalk.com/topapi/v2/user/get?access_token=";

                string postData = JsonConvert.SerializeObject(new
                {
                    userid = userId,
                    language = "zh_CN"
                });
                var result = WebApiHelper.CallPostWebApi(url + _accessToken, postData);
                JObject jObject = JObject.Parse(result);
                string erro = jObject["errcode"].ToString();
                if (erro == "88")//accessToken失效
                {
                    GetAccessToken();
                    result = WebApiHelper.CallPostWebApi(url + _accessToken, postData);
                    jObject = JObject.Parse(result);
                }
                else if (erro != "0")
                {
                    throw new Exception("钉钉获取用户详情失败" + erro + jObject["sub_msg"].ToString());
                }
                userInfo = JsonConvert.DeserializeObject<DingUserInfoModel>(jObject["result"].ToString());
            }
            catch (Exception e)
            {
                throw e;
            }
            return userInfo;
        }
        /// <summary>
        /// 获取审批钉盘空间信息
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public string GetAttachSpaceID(string userId)
        {
            string spaceId = "";
            string url = "https://api.dingtalk.com/v1.0/workflow/processInstances/spaces/infos/query";//?x-acs-dingtalk-access-token=
            string postData = JsonConvert.SerializeObject(new
            {
                userId = userId,
                agentId = _agentId
            });
            try
            {
                Dictionary<string, string> headers = new Dictionary<string, string>();
                headers.Add("x-acs-dingtalk-access-token", _accessToken);
                string result = WebApiHelper.Post(url, headers, postData);
                JObject jObject = JObject.Parse(result);
                string erro = jObject["success"] == null ? jObject["code"].ToString() : jObject["success"].ToString();
                if (erro != "True" && erro != "InvalidAuthentication")
                {
                    throw new Exception("钉钉获取用户详情失败" + erro + jObject["message"].ToString());
                }
                else if (erro == "InvalidAuthentication")//Token失效
                {
                    GetAccessToken();
                    headers = new Dictionary<string, string>();
                    headers.Add("x-acs-dingtalk-access-token", _accessToken);
                    result = WebApiHelper.Post(url, headers, postData);
                    jObject = JObject.Parse(result);
                }
                spaceId = jObject["result"]["spaceId"].ToString();
            }
            catch (Exception e)
            {
                throw e;
            }
            return spaceId;
        }
        /// <summary>
        /// 获取审批钉盘空间信息
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public string CreateFolder(string unionid, string spaceId, string fileName)
        {
            string uuId = "";
            string url = string.Format("https://api.dingtalk.com/v1.0/storage/spaces/{0}/dentries/0/folders?unionId={1}", spaceId, unionid);//?x-acs-dingtalk-access-token=
            string postData = JsonConvert.SerializeObject(new
            {
                name = fileName,
                option = new
                {
                    conflictStrategy = "RETURN_DENTRY_IF_EXISTS",
                    appProperties = new List<object> 
                    {
                        new {
                            name = "AgentID",
                            value = _agentId.ToString(),
                            visibility = "PUBLIC"
                        }
                    }
                }
            });
            try
            {
                Dictionary<string, string> headers = new Dictionary<string, string>();
                headers.Add("x-acs-dingtalk-access-token", _accessToken);
                string result = WebApiHelper.Post(url, headers, postData);
                JObject jObject = JObject.Parse(result);
                string erro = jObject["dentry"] == null ? jObject["code"].ToString() : jObject["dentry"]["status"].ToString();
                if (erro != "NORMAL" && erro != "InvalidAuthentication")
                {
                    throw new Exception("钉钉创建文件夹失败" + erro + jObject["message"].ToString());
                }
                else if (erro == "InvalidAuthentication")//Token失效
                {
                    GetAccessToken();
                    headers = new Dictionary<string, string>();
                    headers.Add("x-acs-dingtalk-access-token", _accessToken);
                    result = WebApiHelper.Post(url, headers, postData);
                    jObject = JObject.Parse(result);
                }
                uuId = jObject["dentry"]["uuid"].ToString();
            }
            catch (Exception e)
            {
                throw e;
            }
            return uuId;
        }

        /// <summary>
        /// 为文件夹添加管理员权限
        /// </summary>
        /// <param name="uuId"></param>
        /// <param name="unionId"></param>
        /// <param name="userId"></param>
        public bool AddFolderPermission(string uuId, string unionId, string userId)
        {
            bool success = false;
            string url = string.Format("https://api.dingtalk.com/v2.0/storage/spaces/dentries/{0}/permissions?unionId={1}", uuId, unionId);//?x-acs-dingtalk-access-token=
            string postData = JsonConvert.SerializeObject(new
            {
                roleId = "MANAGER",
                members = new List<Object>{
                    new {
                        type="USER",
                        id = userId,
                        corpId = _corpId
                    }
                },
                option = new
                {
                    duration = 3600
                }
            });
            try
            {
                Dictionary<string, string> headers = new Dictionary<string, string>();
                headers.Add("x-acs-dingtalk-access-token", _accessToken);
                string result = WebApiHelper.Post(url, headers, postData);
                JObject jObject = JObject.Parse(result);
                string erro = jObject["success"] == null ? jObject["code"].ToString() : jObject["success"].ToString();
                if (erro != "True" && erro != "InvalidAuthentication")
                {
                    throw new Exception("钉钉创建文件夹失败" + erro + jObject["message"].ToString());
                }
                else if (erro == "InvalidAuthentication")//Token失效
                {
                    GetAccessToken();
                    headers = new Dictionary<string, string>();
                    headers.Add("x-acs-dingtalk-access-token", _accessToken);
                    result = WebApiHelper.Post(url, headers, postData);
                    jObject = JObject.Parse(result);
                }
                success = jObject["success"].ToString() == "True";
            }
            catch (Exception e)
            {
                throw e;
            }
            return success;
        }
        /// <summary>
        /// 获取文件上传信息
        /// </summary>
        /// <param name="unionId"></param>
        /// <param name="spaceId"></param>
        /// <param name="folderUUID"></param>
        /// <returns></returns>
        public UpLoadInfoModel GetFileUploadInfo(string unionId, string spaceId, string folderUUID)
        {
            UpLoadInfoModel model = null;
            string url = string.Format("https://api.dingtalk.com/v1.0/storage/spaces/{0}/files/uploadInfos/query?unionId={1}", spaceId, unionId);//?x-acs-dingtalk-access-token=
            string postData = JsonConvert.SerializeObject(new
            {
                protocol = "HEADER_SIGNATURE",
                multipart = false,
                option = new
                {
                    storageDriver = "DINGTALK",
                    preferRegion = "ZHANGJIAKOU",
                    preferIntranet = false,

                }
            });
            try
            {
                Dictionary<string, string> headers = new Dictionary<string, string>();
                headers.Add("x-acs-dingtalk-access-token", _accessToken);
                string result = WebApiHelper.Post(url, headers, postData);
                JObject jObject = JObject.Parse(result);
                string erro = jObject["code"] != null ? jObject["code"].ToString() : "True";
                if (erro != "True" && erro != "InvalidAuthentication")
                {
                    throw new Exception("钉钉获取文件上传信息失败" + erro + jObject["message"].ToString());
                }
                else if (erro == "InvalidAuthentication")//Token失效
                {
                    GetAccessToken();
                    headers = new Dictionary<string, string>();
                    headers.Add("x-acs-dingtalk-access-token", _accessToken);
                    result = WebApiHelper.Post(url, headers, postData);
                    jObject = JObject.Parse(result);
                }
                model = JsonConvert.DeserializeObject<UpLoadInfoModel>(result);
            }
            catch (Exception e)
            {
                throw e;
            }
            return model;
        }

        /// <summary>
        /// 使用OSS的header加签方式上传文件
        /// </summary>
        /// <param name="url"></param>
        /// <param name="filePath"></param>
        /// <param name="headers"></param>
        /// <param name="urlType">文件链接类型1网络资源、2本地文件</param>
        /// <returns></returns>
        public static string HttpRequest(string url, string filePath, Dictionary<string, string> headers, int urlType = 1)
        {
            byte[] datas = null;
            if (urlType == 1)
            {
                datas = new HttpRequestUntil().getFileByte(filePath);
            }
            else
            {
                datas = File.ReadAllBytes(filePath);
            }
            //FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
            //BinaryReader reader = new BinaryReader(fileStream);
            //reader.BaseStream.Seek(0, SeekOrigin.Begin);
            //byte[] datas = reader.ReadBytes((int)reader.BaseStream.Length);
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "PUT";
            request.Timeout = 150000;
            foreach (var header in headers)
            {
                request.Headers.Add(header.Key, header.Value);
            }
            Stream requestStream = null;
            string responseStr = null;
            try
            {
                if (datas != null)
                {
                    request.ContentLength = datas.Length;
                    requestStream = request.GetRequestStream();
                    requestStream.Write(datas, 0, datas.Length);
                    requestStream.Close();
                }
                else
                {
                    request.ContentLength = 0;
                }
                HttpWebResponse response = request.GetResponse() as HttpWebResponse;
                responseStr = response.Headers.GetValues("x-oss-request-id")[0];
            }
            catch (Exception ex)
            {
                Console.WriteLine("error");
            }
            finally
            {
                request = null;
                requestStream = null;
            }
            return responseStr;
        }

        /// <summary>
        /// 提交文件
        /// </summary>
        /// <param name="uuId"></param>
        /// <param name="unionId"></param>
        /// <param name="uploadKey"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public DingFileInfoModel commitFile(string uuId, string unionId, string uploadKey, string name)
        {
            DingFileInfoModel model = null;
            string url = string.Format("https://api.dingtalk.com/v2.0/storage/spaces/files/{0}/commit?unionId={1}", uuId, unionId);//?x-acs-dingtalk-access-token=
            string postData = JsonConvert.SerializeObject(new
            {
                uploadKey = uploadKey,
                name = name,
                option = new
                {
                    conflictStrategy = "AUTO_RENAME",
                    appProperties = new List<Object>{
                    new {
                        name="AgentID",
                        value = _agentId.ToString(),
                        visibility = "PUBLIC"
                    }
                }

                }
            });
            try
            {
                Dictionary<string, string> headers = new Dictionary<string, string>();
                headers.Add("x-acs-dingtalk-access-token", _accessToken);
                string result = WebApiHelper.Post(url, headers, postData);
                JObject jObject = JObject.Parse(result);
                string erro = jObject["code"] != null ? jObject["code"].ToString() : "True";
                if (erro != "True" && erro != "InvalidAuthentication")
                {
                    throw new Exception("钉钉提交文件失败" + erro + jObject["message"].ToString());
                }
                else if (erro == "InvalidAuthentication")//Token失效
                {
                    GetAccessToken();
                    headers = new Dictionary<string, string>();
                    headers.Add("x-acs-dingtalk-access-token", _accessToken);
                    result = WebApiHelper.Post(url, headers, postData);
                    jObject = JObject.Parse(result);
                }
                model = JsonConvert.DeserializeObject<DingFileInfoModel>(result);
            }
            catch (Exception e)
            {
                throw e;
            }
            return model;
        }
        /// <summary>
        /// 通过ProcessCode获取表单schema
        /// </summary>
        /// <param name="processCode"></param>
        /// <returns></returns>
        public SchemaContentModel QuerySchemaByProcessCode(string processCode)
        {
            SchemaContentModel model = null;
            string url = string.Format("https://api.dingtalk.com/v1.0/workflow/forms/schemas/processCodes?processCode={0}", processCode);//
            try
            {
                Dictionary<string, string> headers = new Dictionary<string, string>();
                headers.Add("x-acs-dingtalk-access-token", _accessToken);
                Dictionary<string, string> para = new Dictionary<string, string>();
                string result = WebApiHelper.Get(url, headers, para);
                JObject jObject = JObject.Parse(result);
                string erro = jObject["code"] != null ? jObject["code"].ToString() : "True";
                if (erro != "True" && erro != "InvalidAuthentication")
                {
                    throw new Exception("钉钉提交文件失败" + erro + jObject["message"].ToString());
                }
                else if (erro == "InvalidAuthentication")//Token失效
                {
                    GetAccessToken();
                    headers = new Dictionary<string, string>();
                    headers.Add("x-acs-dingtalk-access-token", _accessToken);
                    result = WebApiHelper.Get(url, headers, para);
                    jObject = JObject.Parse(result);
                }
                model = JsonConvert.DeserializeObject<SchemaContentModel>(result);
            }
            catch (Exception e)
            {
                throw e;
            }
            return model;
        }

        /// <summary>
        /// 创建付款申请审批
        /// </summary>
        /// <param name="uuId"></param>
        /// <param name="unionId"></param>
        /// <param name="uploadKey"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public string CreatePayApplyProcess(DingUserInfoModel userInfo, string processCode, SchemaContentModel schemaModel, List<DingFileInfoModel> attachFiles)
        {
            string instanceId = null;
            string url = "https://api.dingtalk.com/v1.0/workflow/processInstances";//?x-acs-dingtalk-access-token=
            List<Object> attachs = new List<Object>();
            attachFiles.ForEach(att =>
            {
                attachs.Add(new
                {
                    spaceId = att.dentry.spaceId,
                    fileId = att.dentry.id,
                    fileName = att.dentry.name,
                    fileSize = att.dentry.size,
                    fileType = att.dentry.type
                });
            });
            var formComponents = new List<Object>();
            schemaModel.result.schemaContent.items.ForEach(item =>
            {
                string value = "";
                switch (item.props.label)
                {
                    case "付款事由":
                        value = "付款事由";
                        break;
                    case "供应商":
                        value = "供应商";
                        break;
                    case "要求付款日":
                        value = DateTime.Now.ToString("yyyy-MM-dd");
                        break;
                    case "收款开户行":
                        value = "收款开户行";
                        break;
                    case "供应商收款账户":
                        value = "供应商收款账户";
                        break;
                    case "付款金额":
                        value = "60";
                        break;
                    case "附件":
                        value = Newtonsoft.Json.JsonConvert.SerializeObject(attachs);
                        break;
                    default:
                        break;
                }
                formComponents.Add(new
                {
                    id = item.props.id,
                    bizAlias = item.props.bizAlias,
                    name = item.props.label,
                    componentType = item.componentName,
                    value = value
                });
            });
            string postData = JsonConvert.SerializeObject(new
            {
                originatorUserId = userInfo.userid,
                processCode = processCode,
                microappAgentId = _agentId,
                deptId = userInfo.leader_in_dept.FirstOrDefault().dept_id,
                ccPosition = "START_FINISH",
                formComponentValues = formComponents
            });
            try
            {
                Dictionary<string, string> headers = new Dictionary<string, string>();
                headers.Add("x-acs-dingtalk-access-token", _accessToken);
                string result = WebApiHelper.Post(url, headers, postData);
                JObject jObject = JObject.Parse(result);
                string erro = jObject["code"] != null ? jObject["code"].ToString() : "True";
                if (erro != "True" && erro != "InvalidAuthentication")
                {
                    throw new Exception("钉钉发起审批实例失败" + erro + jObject["message"].ToString());
                }
                else if (erro == "InvalidAuthentication")//Token失效
                {
                    GetAccessToken();
                    headers = new Dictionary<string, string>();
                    headers.Add("x-acs-dingtalk-access-token", _accessToken);
                    result = WebApiHelper.Post(url, headers, postData);
                    jObject = JObject.Parse(result);
                }
                instanceId = jObject["instanceId"].ToString();
            }
            catch (Exception e)
            {
                throw e;
            }
            return instanceId;
        }
    }
}
